package com.allwees.core.common.util.encrypt;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 实现AES对称可逆加密，明文经AES加密后再用Base64编码一遍后输出，解密反之
 *
 * @author yangylsky
 */
public class AES extends Encryptor {
	public static final String DefaultSeed = "QSCGYj1r2y3q4157687~!@#&";

	private static final String ALGORITHM_MD5 = "md5";

	private static final String CHARSET = "UTF-8";

	private static final String ALGORITHM_AES = "AES";

	public static String encrypt(String source) {
		return encrypt(source, DefaultSeed);
	}

	public static String encrypt(String source, String seed) {
		try {
			return encryptBASE64(encryptOrDecrypt(source.getBytes(CHARSET), getAESKeyBytes(seed), Cipher.ENCRYPT_MODE));
		} catch(UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public static String decrypt(String encryptData) {
		return decrypt(encryptData, DefaultSeed);
	}

	public static String decrypt(String encryptData, String seed) {
		return new String(encryptOrDecrypt(decryptBASE64(encryptData), getAESKeyBytes(seed), Cipher.DECRYPT_MODE));
	}

	/**
	 * 加密或解密。加密和解密用的同一个算法和密钥
	 *
	 * @param source
	 *            要加密或解密的数据
	 * @param key
	 *            密钥。密钥长度必须为16，不能多也不能少，否则抛【InvalidKeyException: Invalid AES key length】
	 * @param mode
	 *            加密或解密模式。值请选择Cipher.DECRYPT_MODE或Cipher.ENCRYPT_MODE
	 * @return 加密或解密后的数据
	 */
	private static byte[] encryptOrDecrypt(byte[] source, byte[] key, int mode) {
		try {
			Cipher cipher = Cipher.getInstance(ALGORITHM_AES);
			Key keyAES = new SecretKeySpec(key, ALGORITHM_AES);
			cipher.init(mode, keyAES);
			return cipher.doFinal(source);
		} catch(NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 根据字符串生成AES的密钥字节数组(这个方法的目的只是保证密钥长度为16，具体的算法可以任意)
	 */
	public static byte[] getAESKeyBytes(String sKey) {
		try {
			MessageDigest md = MessageDigest.getInstance(ALGORITHM_MD5);
			md.update(sKey.getBytes(CHARSET));
			return md.digest();
		} catch(NoSuchAlgorithmException | UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
}
